home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / domain.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  60KB  |  2,538 lines

  1.  /*
  2.  *      DOMAIN.C -- domain name system stub resolver
  3.  *
  4.  *      Original code by Phil Karn, KA9Q.
  5.  *
  6.  *      Apr 90  Bill Simpson added address->name resolution, time-to-live,
  7.  *      thru    memory caching, generalized multi-record multi-type searches,
  8.  *      Oct 90  and many minor changes to conform more closely to the RFCs.
  9.  *      Feb 91  Bill Simpson added "query" command and TYPE_ANY processing.
  10.  *      Jul 91  Bill Simpson added "more" sessions for query and cache list.
  11.  *
  12.  *      ATARI Version by David Nash - dnash@chaos.demon.co.uk
  13.  */
  14.  
  15. /****************************************************************************
  16. *       $Id: domain.c 1.5 94/01/04 14:09:08 ROOT_DOS Exp $
  17.  
  18. *  07 Jun 92    1.2    GT Reset DNS timeout on DNS failure.
  19. *        Oct 92     -   mt@kram.demon.co.uk (G7LEU) merged NOS WG7J104 DNS code.
  20. *        Feb 93     -   lonewolf@sphere.demon.co.uk fixed DNS reply to TYPE_ANY
  21. *                            query.  Added domain qtype <n> to set the query type used
  22. *                        by domain query. Useful if your server doesn't understand
  23. *                     TYPE_ANY changed all remaining printf to tprintf.
  24. *    17 May 93    1.4    GT    Fix warnings.    
  25. *    24 Dec 93    1.5    GT    Fix conditionals.
  26. ****************************************************************************/
  27.  
  28. #include <stdio.h>
  29. #include <ctype.h>
  30. #include <time.h>
  31. #ifdef ATARI
  32. #include <sys/types.h>
  33. #endif
  34. #include <sys/stat.h>
  35. #ifndef ATARI
  36. #include <dir.h>
  37. #else
  38. #include <sys/dir.h>
  39. #endif
  40. #include <dos.h>
  41. #include <string.h>
  42. #include <stdarg.h>
  43. #include "global.h"
  44. #include "config.h"
  45. #include "mbuf.h"
  46. #include "proc.h"
  47. #include "ip.h"
  48. #include "netuser.h"
  49. #include "session.h"
  50. #include "socket.h"
  51. #include "cmdparse.h"
  52. #include "commands.h"
  53. #include "files.h"
  54. #include "main.h"
  55. #include "domain.h"
  56.  
  57. #undef  DEBUG                           /* for certain trace messages */
  58. #undef  DEBUG_PAIN                      /* for painful debugging */
  59.  
  60. static struct rr *Dcache = NULLRR;      /* Cache of resource records */
  61. static int Dcache_size = 20;            /* size limit */
  62. static time_t Dcache_time = 0L;         /* timestamp */
  63.  
  64. static int Dfile_clean = FALSE;         /* discard expired records (flag) */
  65. static int Dfile_reading = 0;           /* read interlock (count) */
  66. static int Dfile_writing = 0;           /* write interlock (count) */
  67.  
  68. struct proc *Dfile_updater = NULLPROC;
  69. static int32 Dfile_wait_absolute = 0L;  /* timeout Clock time */
  70. static int Dfile_wait_relative = 300;   /* timeout file activity (seconds) */
  71.  
  72. static struct dserver *Dservers = NULLDOM; /* List of potential servers */
  73. static int Dserver_retries = 2;         /* Attempts to reach servers */
  74. static int32 Dserver_maxwait = 0L;      /* maximum server timeout limit (seconds) */
  75.  
  76. static char *Dsuffix = NULLCHAR;        /* Default suffix for names without periods */
  77. static int Dtrace = FALSE;
  78. static int qtype = 255;
  79.  
  80. static char *Dtypes[] = {
  81.     "",
  82.     "A",
  83.     "NS",
  84.     "MD",
  85.     "MF",
  86.     "CNAME",
  87.     "SOA",
  88.     "MB",
  89.     "MG",
  90.     "MR",
  91.     "NULL",
  92.     "WKS",
  93.     "PTR",
  94.     "HINFO",
  95.     "MINFO",
  96.     "MX",
  97.     "TXT"
  98. };
  99. static int Ndtypes = 17;
  100. static char delim[] = " \t\r\n";
  101.  
  102. #ifdef DSERVER
  103. static struct DOM_FILE {
  104.     struct DOM_FILE *next;
  105.     char type;
  106.     char *filename;
  107.     char *domain;
  108.     int32 source;
  109.     struct soa dom_soa;
  110.     } *dom_file = NULL;
  111. struct proc *Drx;
  112. int Dsocket;
  113. extern char *Dzones;
  114. extern char *Dboot;
  115. #endif
  116.  
  117. extern int are_we_an_mx;
  118.  
  119. static int docache __ARGS((int argc,char *argv[],void *p));
  120. static int dosuffix __ARGS((int argc,char *argv[],void *p));
  121.  
  122. static int docacheclean __ARGS((int argc,char *argv[],void *p));
  123. static int __stdargs docachelist __ARGS((int argc,char *argv[],void *p));
  124. static int docachesize __ARGS((int argc,char *argv[],void *p));
  125. static int docachewait __ARGS((int argc,char *argv[],void *p));
  126.  
  127. static void dlist_add __ARGS((struct dserver *dp));
  128. static void dlist_drop __ARGS((struct dserver *dp));
  129. static int dodnsadd __ARGS((int argc,char *argv[],void *p));
  130. static int dodnsdrop __ARGS((int argc,char *argv[],void *p));
  131. static int dodnslist __ARGS((int argc,char *argv[],void *p));
  132. static int dodnsmaxw __ARGS((int argc,char *argv[],void *p));
  133. static int __stdargs dodnsquery __ARGS((int argc,char *argv[],void *p));
  134. static int dodnsretry __ARGS((int argc,char *argv[],void *p));
  135. static int dodnstrace __ARGS((int argc,char *argv[],void *p));
  136. static int __stdargs doqtype __ARGS((int argc,char *argv[],void *p));
  137.  
  138. static char * dtype __ARGS((int value));
  139. static int check_ttl __ARGS((struct rr *rrlp));
  140. static int compare_rr __ARGS((struct rr *search_rrp,struct rr *target_rrp));
  141. static int compare_rr_list __ARGS((struct rr *rrlp,struct rr *target_rrp));
  142. static struct rr *copy_rr __ARGS((struct rr *rrp));
  143. static struct rr *copy_rr_list __ARGS((struct rr *rrlp));
  144. static struct rr *make_rr __ARGS((int source, char *dname,int16 class,int16 type,int32 ttl,int16 rdl,void *data));
  145.  
  146. static void dcache_add __ARGS((struct rr *rrlp));
  147. static void dcache_drop __ARGS((struct rr *rrp));
  148. static struct rr *dcache_search __ARGS((struct rr *rrlp));
  149. static void dcache_update __ARGS((struct rr *rrlp));
  150.  
  151. static struct rr *get_rr __ARGS((FILE *fp, struct rr *lastrrp));
  152. static void put_rr __ARGS((FILE *fp,struct rr *rrp));
  153. static struct rr *dfile_search __ARGS((struct rr *rrlp, char *filename));
  154. static void __stdargs dfile_update __ARGS((int s,void *unused,void *p));
  155.  
  156. static void dumpdomain __ARGS((struct dhdr *dhp,int32 rtt));
  157. static int dns_makequery __ARGS((int16 op,struct rr *rrp, char *buffer,int16 buflen));
  158. static void dns_query __ARGS((struct rr *rrlp));
  159.  
  160. static int isaddr __ARGS((char *s));
  161. static char *checksuffix __ARGS((char *dname));
  162. static struct rr *resolver __ARGS((struct rr *rrlp));
  163.  
  164. #ifdef DSERVER
  165. static void free_dhdr __ARGS((struct dhdr *));
  166. static void __stdargs proc_query __ARGS((int,void *,void *));
  167. static void __stdargs drx __ARGS((int,void *,void *));
  168. static int dodnsserver __ARGS((int argc,char *argv[],void *p));
  169. static int dostopdnsserver __ARGS((int argc,char *argv[],void *p));
  170. #endif
  171.  
  172. /**
  173.  **     Domain Resolver Commands
  174.  **/
  175.  
  176. static struct cmds Dcmds[] = {
  177.     { "addserver",    dodnsadd,       0, 2, "add <hostid>" },
  178.     { "dropserver",   dodnsdrop,      0, 2, "drop <hostid>" },
  179.     { "list",         dodnslist,      0, 0, NULLCHAR },
  180.     { "maxwait",      dodnsmaxw,      0, 0, NULLCHAR },
  181.     { "query",        dodnsquery,   512, 2, "query <hostid>" },
  182.     { "qtype",        doqtype,        0, 0, NULLCHAR },
  183.     { "retry",        dodnsretry,     0, 0, NULLCHAR },
  184.     { "suffix",       dosuffix,       0, 0, NULLCHAR },
  185. #ifdef DSERVER
  186.     { "startdns", dodnsserver,0, 0, NULLCHAR },
  187.     { "stopdns", dostopdnsserver,0, 0, NULLCHAR },
  188. #endif
  189.     { "trace",        dodnstrace,     0, 0, NULLCHAR },
  190.     { "cache",        docache,        0, 0, NULLCHAR },
  191.     { NULLCHAR },
  192. };
  193.  
  194. static struct cmds Dcachecmds[] = {
  195.     { "clean",        docacheclean,   0, 0, NULLCHAR },
  196.     { "list",         docachelist,  512, 0, NULLCHAR },
  197.     { "size",         docachesize,    0, 0, NULLCHAR },
  198.     { "wait",         docachewait,    0, 0, NULLCHAR },
  199.     { NULLCHAR },
  200. };
  201.  
  202. int
  203. dodomain(argc,argv,p)
  204. int argc;
  205. char *argv[];
  206. void *p;
  207. {
  208.     return subcmd(Dcmds,argc,argv,p);
  209. }
  210.  
  211. static int
  212. docache(argc,argv,p)
  213. int argc;
  214. char *argv[];
  215. void *p;
  216. {
  217.     return subcmd(Dcachecmds,argc,argv,p);
  218. }
  219.  
  220. static int
  221. dosuffix(argc,argv,p)
  222. int argc;
  223. char *argv[];
  224. void *p;
  225. {
  226.     if(argc < 2){
  227.         if(Dsuffix != NULLCHAR)
  228.             tprintf("%s\n",Dsuffix);
  229.         return 0;
  230.     }
  231.     free(Dsuffix);
  232.     Dsuffix = strdup(argv[1]);
  233.     return 0;
  234. }
  235.  
  236. static
  237. dodnsmaxw(argc,argv,p)
  238. int argc;
  239. char *argv[];
  240. void *p;
  241. {
  242.     return setlong(&Dserver_maxwait,"Server response timeout limit (sec)",argc,argv);
  243. }
  244.  
  245. static int
  246. docacheclean(argc,argv,p)
  247. int argc;
  248. char *argv[];
  249. void *p;
  250. {
  251.     return setbool( &Dfile_clean, "discard expired records", argc,argv );
  252. }
  253.  
  254. static int __stdargs
  255. docachelist(argc,argv,p)
  256. int argc;
  257. char *argv[];
  258. void *p;
  259. {
  260.     struct rr *rrp;
  261.     struct session *sp;
  262.     int row = MOREROWS;
  263.  
  264.     if((sp = newsession(argv[1],DCLIST)) == NULLSESSION){
  265.         return -1;
  266.     }
  267.  
  268.     (void)dcache_search(NULLRR); /* update ttl */
  269.  
  270.     /* Put tty into raw mode so single-char responses will work */
  271.     sp->ttystate.echo = sp->ttystate.edit = 0;
  272.  
  273.     for(rrp=Dcache;rrp!=NULLRR;rrp=rrp->next)
  274.     {
  275.         put_rr(stdout,rrp);
  276.         if(--row == 0){
  277.             row = keywait("--More--",0);
  278.             switch(row){
  279.             case -1:
  280.             case 'q':
  281.             case 'Q':
  282.                 rrp = NULLRR;
  283.                 break;
  284.             case '\n':
  285.             case '\r':
  286.                 row = 1;
  287.                 break;
  288.             case ' ':
  289.             default:
  290.                 row = MOREROWS;
  291.             };
  292.         }
  293.     }
  294.     fflush(stdout);
  295.     keywait(NULLCHAR,1);
  296.     freesession(sp);
  297.     return 0;
  298. }
  299.  
  300. static int
  301. docachesize(argc,argv,p)
  302. int argc;
  303. char *argv[];
  304. void *p;
  305. {
  306.     int newsize;
  307.     int oldsize;
  308.     int result;
  309.  
  310.     newsize = oldsize = Dcache_size;
  311.     result = setint( &newsize, "memory cache size", argc,argv );
  312.  
  313.     if(newsize > 0){
  314.         Dcache_size = newsize;
  315.         if(newsize < oldsize){
  316.             (void)dcache_search(NULLRR); /* update size */
  317.         }
  318.     }
  319.     return result;
  320. }
  321.  
  322. static int
  323. docachewait(argc,argv,p)
  324. int argc;
  325. char *argv[];
  326. void *p;
  327. {
  328.     return setint( &Dfile_wait_relative, "time before file update (seconds)", argc,argv );
  329. }
  330.  
  331. static void
  332. dlist_add(dp)
  333. register struct dserver *dp;
  334. {
  335.     dp->prev = NULLDOM;
  336.     dp->next = Dservers;
  337.     if(Dservers != NULLDOM)
  338.         Dservers->prev = dp;
  339.     Dservers = dp;
  340. }
  341.  
  342. static void
  343. dlist_drop(dp)
  344. register struct dserver *dp;
  345. {
  346.     if(dp->prev != NULLDOM)
  347.         dp->prev->next = dp->next;
  348.     else
  349.         Dservers = dp->next;
  350.     if(dp->next != NULLDOM)
  351.         dp->next->prev = dp->prev;
  352. }
  353.  
  354. static int
  355. dodnsadd(argc,argv,p)
  356. int argc;
  357. char *argv[];
  358. void *p;
  359. {
  360.     int32 address;
  361.  
  362.     if((address = resolve(argv[1])) == 0L){
  363.         tprintf("Resolver %s unknown\n",argv[1]);
  364.         return 1;
  365.     }
  366.     return add_nameserver(address);
  367. }
  368. int
  369. add_nameserver(address)
  370. int32 address;
  371. {
  372.     struct dserver *dp;
  373.  
  374.     dp = (struct dserver *)callocw(1,sizeof(struct dserver));
  375.     dp->address = address;
  376.     dp->srtt = 5000L; /* 5 sec */
  377.     dp->mdev = 0;
  378.     dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  379.     dlist_add(dp);
  380.     return 0;
  381. }
  382.  
  383. static int
  384. dodnsdrop(argc,argv,p)
  385. int argc;
  386. char *argv[];
  387. void *p;
  388. {
  389.     struct dserver *dp;
  390.     int32 addr;
  391.  
  392.     addr = resolve(argv[1]);
  393.     for(dp = Dservers;dp != NULLDOM;dp = dp->next)
  394.         if(addr == dp->address)
  395.             break;
  396.  
  397.     if(dp == NULLDOM){
  398.         tprintf("Not found\n");
  399.         return 1;
  400.     }
  401.  
  402.     dlist_drop(dp);
  403.     free((char *)dp);
  404.     return 0;
  405. }
  406.  
  407. static int
  408. dodnslist(argc,argv,p)
  409. int argc;
  410. char *argv[];
  411. void *p;
  412. {
  413. #ifdef DSERVER
  414.     struct DOM_FILE *t_dom_file;
  415. #endif
  416.     register struct dserver *dp;
  417.  
  418.     tprintf("Server address          srtt    mdev    timeout  queries responses timeouts\n");
  419.     for(dp = Dservers;dp != NULLDOM;dp = dp->next){
  420.         tprintf("%-20s%8lu%8lu%10lu%10lu%10lu%10lu\n",
  421.          inet_ntoa(dp->address),
  422.          dp->srtt,dp->mdev,dp->timeout,
  423.          dp->queries,dp->responses,dp->timeouts);
  424.     }
  425. #ifdef DSERVER
  426.     if (Drx == NULLPROC)
  427.         tprintf("Domain Name Server not running.\n");
  428.     else tprintf("Domain Name Server running.\n");
  429.     t_dom_file = dom_file;
  430.     while(Drx != NULLPROC && t_dom_file)
  431.         {
  432.         if (t_dom_file->type == '1')
  433.             tprintf("We are primary for %s\n", t_dom_file->domain);
  434.         else if (t_dom_file->type == '2')
  435.             tprintf("We are secondary for %s (from %s)\n",
  436.                             t_dom_file->domain, inet_ntoa(t_dom_file->source));
  437.         t_dom_file = t_dom_file->next;
  438.         }
  439. #endif
  440.     return 0;
  441. }
  442.  
  443. static int __stdargs
  444. doqtype(argc,argv,p)
  445. int argc;
  446. char *argv[];
  447. void *p;
  448. {
  449.     return setint(&qtype,"Query type",argc,argv);
  450. }
  451.  
  452. static int __stdargs
  453. dodnsquery(argc,argv,p)
  454. int argc;
  455. char *argv[];
  456. void *p;
  457. {
  458.     struct rr *rrp;
  459.     struct rr *result_rrlp;
  460.     char *sname;
  461.     struct session *sp;
  462.     int row = MOREROWS;
  463.  
  464.     if((sp = newsession(argv[1],DQUERY)) == NULLSESSION){
  465.         return -1;
  466.     }
  467.  
  468.     if ( isaddr( argv[1] ) ) {
  469.         result_rrlp = inverse_a( aton( argv[1] ) );
  470.     } else {
  471.         sname = checksuffix( argv[1] );
  472.         rrp = make_rr(RR_QUERY,sname,CLASS_IN,qtype,0,0,NULL);
  473.         free(sname);
  474.  
  475.         dns_query(rrp);
  476.         result_rrlp = dcache_search(rrp);
  477.         free_rr(rrp);
  478.     }
  479.  
  480.     /* Put tty into raw mode so single-char responses will work */
  481.     sp->ttystate.echo = sp->ttystate.edit = 0;
  482.  
  483.     for( rrp=result_rrlp; rrp!=NULLRR; rrp=rrp->next)
  484.     {
  485.         put_rr(stdout,rrp);
  486.         if(--row == 0){
  487.             row = keywait("--More--",0);
  488.             switch(row){
  489.             case -1:
  490.             case 'q':
  491.             case 'Q':
  492.                 rrp = NULLRR;
  493.                 break;
  494.             case '\n':
  495.             case '\r':
  496.                 row = 1;
  497.                 break;
  498.             case ' ':
  499.             default:
  500.                 row = MOREROWS;
  501.             };
  502.         }
  503.     }
  504.     fflush(stdout);
  505.     free_rr(result_rrlp);
  506.     keywait(NULLCHAR,1);
  507.     freesession(sp);
  508.     return 0;
  509. }
  510.  
  511. static int
  512. dodnsretry(argc,argv,p)
  513. int argc;
  514. char *argv[];
  515. void *p;
  516. {
  517.     return setint( &Dserver_retries, "server retries", argc,argv );
  518. }
  519.  
  520. static int
  521. dodnstrace(argc,argv,p)
  522. int argc;
  523. char *argv[];
  524. void *p;
  525. {
  526.     return setbool(&Dtrace,"server trace",argc,argv);
  527. }
  528.  
  529.  
  530. /**
  531.  **     Domain Resource Record Utilities
  532.  **/
  533.  
  534. static char *
  535. dtype(value)
  536. int value;
  537. {
  538.     static char buf[10];
  539.  
  540.     if (value < Ndtypes)
  541.         return Dtypes[value];
  542.  
  543.     sprintf( buf, "{%d}", value);
  544.     return buf;
  545. }
  546.  
  547. /* check list of resource records for any expired ones.
  548.  * returns number of expired records.
  549.  */
  550. static int
  551. check_ttl(rrlp)
  552. register struct rr *rrlp;
  553. {
  554.     int count = 0;
  555.  
  556.     while(rrlp != NULLRR){
  557.         if(rrlp->ttl == 0L)
  558.             count++;
  559.         rrlp = rrlp->next;
  560.     }
  561.     return count;
  562. }
  563.  
  564. /* Compare two resource records.
  565.  * returns 0 if match, nonzero otherwise.
  566.  */
  567. static int
  568. compare_rr(search_rrp,target_rrp)
  569. register struct rr *search_rrp,*target_rrp;
  570. {
  571.     int i;
  572.  
  573.     if(search_rrp == NULLRR || target_rrp == NULLRR)
  574.         return -32765;
  575.  
  576.     if(search_rrp->class != target_rrp->class)
  577.         return -32763;
  578.  
  579.     if(search_rrp->type != TYPE_ANY
  580.     && search_rrp->type != target_rrp->type
  581.     && (search_rrp->source != RR_QUERY
  582.      || (target_rrp->type != TYPE_CNAME
  583.       && target_rrp->type != TYPE_PTR)))
  584.         return -32761;
  585.  
  586.     if(search_rrp->source != RR_INQUERY){
  587. /*
  588.         if((i = strlen(search_rrp->name)) != strlen(target_rrp->name))
  589.             return -32759;
  590. */
  591.         i = strlen(target_rrp->name);
  592.         if((i = strnicmp(search_rrp->name,target_rrp->name,i)) != 0)
  593.             return i;
  594.  
  595.         /* match negative records so that they are replaced */
  596.         if(target_rrp->rdlength == 0)
  597.             return 0;
  598.     }
  599.  
  600.     /* if a query has gotten this far, match it */
  601.     if(search_rrp->source == RR_QUERY)
  602.         return 0;
  603.  
  604.     /* ensure negative records don't replace older records */
  605.     if(search_rrp->rdlength == 0)
  606.         return -32757;
  607.  
  608.     /* match expired records so that they are replaced */
  609.     if(search_rrp->source != RR_INQUERY){
  610.         if(target_rrp->ttl == 0L)
  611.             return 0;
  612.     }
  613.  
  614.     /* Note: rdlengths are not compared because they vary depending
  615.      * on the representation (ASCII or encoded) this record was
  616.      * generated from.
  617.      */
  618.  
  619.     switch(search_rrp->type){
  620.     case TYPE_A:
  621.         i = search_rrp->rdata.addr != target_rrp->rdata.addr;
  622.         break;
  623.     case TYPE_CNAME:
  624.     case TYPE_MB:
  625.     case TYPE_MG:
  626.     case TYPE_MR:
  627.     case TYPE_NS:
  628.     case TYPE_PTR:
  629.     case TYPE_TXT:
  630.         i = stricmp(search_rrp->rdata.data,target_rrp->rdata.data);
  631.         break;
  632.     case TYPE_HINFO:
  633.         i = strcmp(search_rrp->rdata.hinfo.cpu,target_rrp->rdata.hinfo.cpu) ||
  634.             strcmp(search_rrp->rdata.hinfo.os,target_rrp->rdata.hinfo.os);
  635.         break;
  636.     case TYPE_MX:
  637.         i = stricmp(search_rrp->rdata.mx.exch,target_rrp->rdata.mx.exch);
  638.         break;
  639.     case TYPE_SOA:
  640.         i = search_rrp->rdata.soa.serial != target_rrp->rdata.soa.serial;
  641.         break;
  642.     default:
  643.         i = -32755;     /* unsupported */
  644.     }
  645.     return i;
  646. }
  647.  
  648. static int
  649. compare_rr_list(rrlp,target_rrp)
  650. register struct rr *rrlp,*target_rrp;
  651. {
  652.     while(rrlp != NULLRR){
  653.         if(compare_rr(rrlp,target_rrp) == 0)
  654.             return 0;
  655. #ifdef DEBUG_PAIN
  656.         if(Dtrace)
  657.             tprintf("%15d %s\n",
  658.                 compare_rr(rrlp,target_rrp),
  659.                 target_rrp->name);
  660. #endif
  661.         rrlp = rrlp->next;
  662.     }
  663.     return -32767;
  664. }
  665.  
  666. /* Make a new copy of a resource record */
  667. static struct rr *
  668. copy_rr(rrp)
  669. register struct rr *rrp;
  670. {
  671.     register struct rr *newrr;
  672.  
  673.     if(rrp == NULLRR)
  674.         return NULLRR;
  675.  
  676.     newrr = (struct rr *)callocw(1,sizeof(struct rr));
  677.     newrr->source = rrp->source;
  678.     newrr->name =   strdup(rrp->name);
  679.     newrr->type =   rrp->type;
  680.     newrr->class =  rrp->class;
  681.     newrr->ttl =    rrp->ttl;
  682.     if((newrr->rdlength = rrp->rdlength) == 0)
  683.         return newrr;
  684.  
  685.     switch(rrp->type){
  686.     case TYPE_A:
  687.         newrr->rdata.addr = rrp->rdata.addr;
  688.         break;
  689.     case TYPE_CNAME:
  690.     case TYPE_MB:
  691.     case TYPE_MG:
  692.     case TYPE_MR:
  693.     case TYPE_NS:
  694.     case TYPE_PTR:
  695.     case TYPE_TXT:
  696.         newrr->rdata.name = strdup(rrp->rdata.name);
  697.         break;
  698.     case TYPE_HINFO:
  699.         newrr->rdata.hinfo.cpu = strdup(rrp->rdata.hinfo.cpu);
  700.         newrr->rdata.hinfo.os = strdup(rrp->rdata.hinfo.os);
  701.         break;
  702.     case TYPE_MX:
  703.         newrr->rdata.mx.pref = rrp->rdata.mx.pref;
  704.         newrr->rdata.mx.exch = strdup(rrp->rdata.mx.exch);
  705.         break;
  706.     case TYPE_SOA:
  707.         newrr->rdata.soa.mname =        strdup(rrp->rdata.soa.mname);
  708.         newrr->rdata.soa.rname =        strdup(rrp->rdata.soa.rname);
  709.         newrr->rdata.soa.serial =       rrp->rdata.soa.serial;
  710.         newrr->rdata.soa.refresh =      rrp->rdata.soa.refresh;
  711.         newrr->rdata.soa.retry =        rrp->rdata.soa.retry;
  712.         newrr->rdata.soa.expire =       rrp->rdata.soa.expire;
  713.         newrr->rdata.soa.minimum =      rrp->rdata.soa.minimum;
  714.         break;
  715.     }
  716.     return newrr;
  717. }
  718.  
  719. static struct rr *
  720. copy_rr_list(rrlp)
  721. register struct rr *rrlp;
  722. {
  723.     register struct rr **rrpp;
  724.     struct rr *result_rrlp;
  725.  
  726. #ifdef ATARI
  727. #pragma ignore 94     /* ignore uninitialised auto warninge for rrlp */
  728. #endif
  729.  
  730.     rrpp = &result_rrlp;
  731.     while(rrlp != NULLRR){
  732.         *rrpp = copy_rr(rrlp);
  733.         rrpp = &(*rrpp)->next;
  734.         rrlp = rrlp->next;
  735.     }
  736.     *rrpp = NULLRR;
  737.     return result_rrlp;
  738. }
  739.  
  740. /* Free (list of) resource records */
  741. void
  742. free_rr(rrlp)
  743. register struct rr *rrlp;
  744. {
  745.     register struct rr *rrp;
  746.  
  747.     while((rrp = rrlp) != NULLRR){
  748.         rrlp = rrlp->next;
  749.  
  750.         free(rrp->comment);
  751.         free(rrp->name);
  752.         if(rrp->rdlength > 0){
  753.             switch(rrp->type){
  754.             case TYPE_A:
  755.                 break;  /* Nothing allocated in rdata section */
  756.             case TYPE_CNAME:
  757.             case TYPE_MB:
  758.             case TYPE_MG:
  759.             case TYPE_MR:
  760.             case TYPE_NS:
  761.             case TYPE_PTR:
  762.             case TYPE_TXT:
  763.                 free(rrp->rdata.name);
  764.                 break;
  765.             case TYPE_HINFO:
  766.                 free(rrp->rdata.hinfo.cpu);
  767.                 free(rrp->rdata.hinfo.os);
  768.                 break;
  769.             case TYPE_MX:
  770.                 free(rrp->rdata.mx.exch);
  771.                 break;
  772.             case TYPE_SOA:
  773.                 free(rrp->rdata.soa.mname);
  774.                 free(rrp->rdata.soa.rname);
  775.                 break;
  776.             }
  777.         }
  778.         free((char *)rrp);
  779.     }
  780. }
  781.  
  782. static struct rr *
  783. make_rr(
  784.     int source,
  785.     char *dname,
  786.     int16 dclass,
  787.     int16 dtype,
  788.     int32 ttl,
  789.     int16 rdl,
  790.     void *data)
  791. {
  792.     register struct rr *newrr;
  793.  
  794.     newrr = (struct rr *)callocw(1,sizeof(struct rr));
  795.     newrr->source = source;
  796.     newrr->name = strdup(dname);
  797.     newrr->class = dclass;
  798.     newrr->type = dtype;
  799.     newrr->ttl = ttl;
  800.     if((newrr->rdlength = rdl) == 0)
  801.         return newrr;
  802.  
  803.     switch(dtype){
  804.     case TYPE_A:
  805.       {
  806.         register int32 *ap = (int32 *)data;
  807.         newrr->rdata.addr = *ap;
  808.         break;
  809.       }
  810.     case TYPE_CNAME:
  811.     case TYPE_MB:
  812.     case TYPE_MG:
  813.     case TYPE_MR:
  814.     case TYPE_NS:
  815.     case TYPE_PTR:
  816.     case TYPE_TXT:
  817.     case TYPE_AXFR: /*##*/
  818.       {
  819.         newrr->rdata.name = strdup((char *)data);
  820.         break;
  821.       }
  822.     case TYPE_HINFO:
  823.       {
  824.         register struct hinfo *hinfop = (struct hinfo *)data;
  825.         newrr->rdata.hinfo.cpu = strdup(hinfop->cpu);
  826.         newrr->rdata.hinfo.os = strdup(hinfop->os);
  827.         break;
  828.       }
  829.     case TYPE_MX:
  830.       {
  831.         register struct mx *mxp = (struct mx *)data;
  832.         newrr->rdata.mx.pref = mxp->pref;
  833.         newrr->rdata.mx.exch = strdup(mxp->exch);
  834.         break;
  835.       }
  836.     case TYPE_SOA:
  837.       {
  838.         register struct soa *soap = (struct soa *)data;
  839.         newrr->rdata.soa.mname =        strdup(soap->mname);
  840.         newrr->rdata.soa.rname =        strdup(soap->rname);
  841.         newrr->rdata.soa.serial =       soap->serial;
  842.         newrr->rdata.soa.refresh =      soap->refresh;
  843.         newrr->rdata.soa.retry =        soap->retry;
  844.         newrr->rdata.soa.expire =       soap->expire;
  845.         newrr->rdata.soa.minimum =      soap->minimum;
  846.         break;
  847.       }
  848.     }
  849.     return newrr;
  850. }
  851.  
  852.  
  853. /**
  854.  **     Domain Cache Utilities
  855.  **/
  856.  
  857. static void
  858. dcache_add(rrlp)
  859. register struct rr *rrlp;
  860. {
  861.     register struct rr *last_rrp;
  862.     struct rr *save_rrp;
  863.  
  864.     if(rrlp == NULLRR)
  865.         return;
  866.  
  867.     save_rrp = rrlp;
  868.     last_rrp = NULLRR;
  869.     while(rrlp != NULLRR){
  870.         rrlp->last = last_rrp;
  871.         last_rrp = rrlp;
  872.         rrlp = rrlp->next;
  873.     }
  874.     last_rrp->next = Dcache;
  875.     if(Dcache != NULLRR)
  876.         Dcache->last = last_rrp;
  877.     Dcache = save_rrp;
  878. }
  879.  
  880. static void
  881. dcache_drop(rrp)
  882. register struct rr *rrp;
  883. {
  884.     if(rrp->last != NULLRR)
  885.         rrp->last->next = rrp->next;
  886.     else
  887.         Dcache = rrp->next;
  888.     if(rrp->next != NULLRR)
  889.         rrp->next->last = rrp->last;
  890.     rrp->last =
  891.     rrp->next = NULLRR;
  892. }
  893.  
  894. /* Search cache for resource records, removing them from the cache.
  895.  * Also, timeout cache entries, and trim cache to size.
  896.  * (Calling with NULLRR is legal -- will timeout & trim only.)
  897.  * Note that an answer from the cache cannot be authoritative, because
  898.  * we cannot guarantee that all the entries remain from a previous request.
  899.  * Returns RR list, or NULLRR if no record found.
  900.  */
  901. static struct rr *
  902. dcache_search(rrlp)
  903. struct rr *rrlp;
  904. {
  905.     register struct rr *rrp, *test_rrp;
  906.     struct rr **rrpp, *result_rrlp;
  907.     int32 elapsed;
  908.     time_t now;
  909.     int count = 0;
  910.  
  911. #ifdef DEBUG
  912.     if(Dtrace && rrlp != NULLRR){
  913.         tprintf("dcache_search: searching for %s\n",rrlp->name);
  914.     }
  915. #endif
  916.  
  917.     elapsed = (int32)(time(&now) - Dcache_time);
  918.     Dcache_time = now;
  919.  
  920.     rrpp = &result_rrlp;
  921.     for(rrp = Dcache; (test_rrp = rrp) != NULLRR;){
  922.         rrp = rrp->next;
  923.                     /* timeout entries */
  924.         if(test_rrp->ttl > 0L
  925.         && (test_rrp->ttl -= elapsed) <= 0L)
  926.             test_rrp->ttl = 0L;
  927.  
  928.         if(compare_rr_list(rrlp,test_rrp) == 0){
  929.             dcache_drop( *rrpp = test_rrp );
  930.             rrpp = &(*rrpp)->next;
  931.         } else if(test_rrp->source == RR_FILE && ++count > Dcache_size){
  932.             dcache_drop(test_rrp);
  933.             free_rr(test_rrp);
  934.         }
  935.     }
  936.     *rrpp = NULLRR;
  937.     return result_rrlp;
  938. }
  939.  
  940. /* Move a list of resource records to the cache, removing duplicates. */
  941. static void
  942. dcache_update(rrlp)
  943. register struct rr *rrlp;
  944. {
  945.     if(rrlp == NULLRR)
  946.         return;
  947.  
  948.     free_rr(dcache_search(rrlp));   /* remove duplicates, first */
  949.     dcache_add(rrlp);
  950. }
  951.  
  952.  
  953. /**
  954.  **     File Utilities
  955.  **/
  956.  
  957. static struct rr *
  958. get_rr(fp,lastrrp)
  959. FILE *fp;
  960. struct rr *lastrrp;
  961. {
  962. #ifndef ATARI
  963.     char *line,*lp,*strtok();
  964. #else
  965.     char *line, *lp;
  966. #endif
  967.     struct rr *rrp;
  968.     char *name,*ttl,*class,*type,*data;
  969.     int i;
  970.  
  971.     line = mallocw(500);
  972.     if(fgets(line,500,fp) == NULL){
  973.         free(line);
  974.         return NULLRR;
  975.         }
  976.  
  977.     if (strchr(line, '('))
  978.         {
  979.         int done;
  980.         char *big_line, *p;
  981.         p = line;
  982.         while (*p && *p != '(')
  983.             p++;
  984.         *p = '\0';
  985.         big_line = mallocw(500);
  986.         if (big_line == NULL)
  987.             {
  988.             free(line);
  989.             return NULLRR;
  990.             }
  991.         strcpy(big_line, line);
  992.         done = FALSE;
  993.         while (fgets(line, 500, fp) && !done)
  994.             {
  995.             if (strchr(line, ')'))
  996.                 done = TRUE;
  997.             p = line;
  998.             while (*p && *p != ')' && *p != ';')
  999.                 p++;
  1000.             *p = '\0';
  1001.             p = line;
  1002.             while (*p && (*p == ' ' || *p == '\t'))
  1003.                 p++;
  1004.             strcat(big_line, " ");
  1005.             strcat(big_line, p);
  1006.             }
  1007.         strcpy(line, big_line);
  1008.         free(big_line);
  1009.         }
  1010.  
  1011.     rrp = (struct rr *)callocw(1,sizeof(struct rr));
  1012.     rrp->source = RR_FILE;
  1013.  
  1014.     if(line[0] == '\0' || line[0] == '#' || line[0] == ';'){
  1015.         rrp->comment = line;
  1016.         return rrp;
  1017.     }
  1018.  
  1019.     if(!isspace(line[0]) || lastrrp == NULLRR){
  1020.         name = strtok(line,delim);
  1021.         lp = NULLCHAR;
  1022.     } else {        /* Name field is missing */
  1023.         name = lastrrp->name;
  1024.         lp = line;
  1025.     }
  1026.     if(name == NULLCHAR || (i = strlen(name)) == 0){
  1027.         rrp->comment = strdup("\n");
  1028.         free(line);
  1029.         return rrp;
  1030.     }
  1031.  
  1032.     if(name[i-1] != '.'){
  1033.         /* Tack on a trailing period if it's not there */
  1034.         /* !!! need to implement $ORIGIN suffix here */
  1035.         rrp->name = mallocw(i+2);
  1036.         strcpy(rrp->name,name);
  1037.         strcat(rrp->name,".");
  1038.     } else
  1039.         rrp->name = strdup(name);
  1040.  
  1041.     ttl = strtok(lp,delim);
  1042.  
  1043.     if(ttl == NULLCHAR || (!isdigit(ttl[0]) && ttl[0] != '-')){
  1044.         /* Optional ttl field is missing */
  1045.         rrp->ttl = TTL_MISSING;
  1046.         class = ttl;
  1047.     } else {
  1048.         rrp->ttl = atol(ttl);
  1049.         class = strtok(NULLCHAR,delim);
  1050.     }
  1051.  
  1052.     if(class == NULLCHAR){
  1053.         /* we're in trouble, but keep processing */
  1054.         rrp->class = CLASS_MISSING;
  1055.         type = class;
  1056.     } else if(class[0] == '<'){
  1057.         rrp->class = atoi(&class[1]);
  1058.         type = strtok(NULLCHAR,delim);
  1059.     } else if(stricmp(class,"IN") == 0){
  1060.         rrp->class = CLASS_IN;
  1061.         type = strtok(NULLCHAR,delim);
  1062.     } else {
  1063.         /* Optional class field is missing; assume IN */
  1064.         rrp->class = CLASS_IN;
  1065.         type = class;
  1066.     }
  1067.  
  1068.     if(type == NULLCHAR){
  1069.         /* we're in trouble, but keep processing */
  1070.         rrp->type = TYPE_MISSING;
  1071.         data = type;
  1072.     } else if(type[0] == '{'){
  1073.         rrp->type = atoi(&class[1]);
  1074.         data = strtok(NULLCHAR,delim);
  1075.     } else {
  1076.         rrp->type = TYPE_MISSING;
  1077.         for(i=1;i<Ndtypes;i++){
  1078.             if(stricmp(type,Dtypes[i]) == 0){
  1079.                 rrp->type = i;
  1080.                 data = strtok(NULLCHAR,delim);
  1081.                 break;
  1082.             }
  1083.         }
  1084.     }
  1085.  
  1086.     if(rrp->type == TYPE_MISSING){
  1087.         data = NULLCHAR;
  1088.     }
  1089.  
  1090.     if(data == NULLCHAR){
  1091.         /* Empty record, just return */
  1092.         free(line);
  1093.         return rrp;
  1094.     }
  1095.     switch(rrp->type){
  1096.     case TYPE_A:
  1097.         rrp->rdlength = 4;
  1098.         rrp->rdata.addr = aton(data);
  1099.         break;
  1100.     case TYPE_CNAME:
  1101.     case TYPE_MB:
  1102.     case TYPE_MG:
  1103.     case TYPE_MR:
  1104.     case TYPE_NS:
  1105.     case TYPE_PTR:
  1106.     case TYPE_TXT:
  1107.         rrp->rdlength = strlen(data);
  1108.         rrp->rdata.name = strdup(data);
  1109.         break;
  1110.     case TYPE_HINFO:
  1111.         rrp->rdlength = strlen(data);
  1112.         rrp->rdata.hinfo.cpu = strdup(data);
  1113.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  1114.             rrp->rdlength += strlen(data);
  1115.             rrp->rdata.hinfo.os = strdup(data);
  1116.         }
  1117.         break;
  1118.     case TYPE_MX:
  1119.         rrp->rdata.mx.pref = atoi(data);
  1120.         rrp->rdlength = 2;
  1121.  
  1122.         /* Get domain name of exchanger */
  1123.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  1124.             rrp->rdlength += strlen(data);
  1125.             rrp->rdata.mx.exch = strdup(data);
  1126.         }
  1127.         break;
  1128.     case TYPE_SOA:
  1129.         /* Get domain name of master name server */
  1130.         rrp->rdlength = strlen(data);
  1131.         rrp->rdata.soa.mname = strdup(data);
  1132.  
  1133.         /* Get domain name of irresponsible person */
  1134.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  1135.             rrp->rdata.soa.rname = strdup(data);
  1136.             rrp->rdlength += strlen(data);
  1137.         }
  1138.         data = strtok(NULLCHAR,delim);
  1139.         rrp->rdata.soa.serial = atol(data);
  1140.         data = strtok(NULLCHAR,delim);
  1141.         rrp->rdata.soa.refresh = atol(data);
  1142.         data = strtok(NULLCHAR,delim);
  1143.         rrp->rdata.soa.retry = atol(data);
  1144.         data = strtok(NULLCHAR,delim);
  1145.         rrp->rdata.soa.expire = atol(data);
  1146.         data = strtok(NULLCHAR,delim);
  1147.         rrp->rdata.soa.minimum = atol(data);
  1148.         rrp->rdlength += 20;
  1149.         break;
  1150.     }
  1151.  
  1152.     /* !!! need to handle trailing comments */
  1153.     free(line);
  1154.     return rrp;
  1155. }
  1156.  
  1157. static void sofprintf(FILE *fp, char * fmt, ...)
  1158.  /*
  1159.     This routine behaves like the standard fprintf() except
  1160.     for when the destination is stdout. In this case write
  1161.     to the current process' output socket.
  1162.  */
  1163.  char * buf;
  1164.  va_list args;
  1165.  buf = mallocw(1024); /* Big enough for most strings... (cf sockuser.c) */
  1166.  va_start(args, fmt);
  1167.  vsprintf(buf, fmt, args);
  1168.  va_end(args);
  1169.  if (fp == stdout)
  1170.     usputs(Curproc->output, buf);
  1171.  else fputs(buf, fp);
  1172.  free(buf);
  1173. }
  1174.  
  1175. /* Print a resource record */
  1176. static void
  1177. put_rr(fp,rrp)
  1178. FILE *fp;
  1179. struct rr *rrp;
  1180. {
  1181.     char * stuff;
  1182.  
  1183.     if(fp == NULLFILE || rrp == NULLRR)
  1184.         return;
  1185.  
  1186.     if(rrp->name == NULLCHAR && rrp->comment != NULLCHAR){
  1187.         sofprintf(fp,"%s",rrp->comment);
  1188.         return;
  1189.     }
  1190.  
  1191.     sofprintf(fp,"%s",rrp->name);
  1192.     if(rrp->ttl != TTL_MISSING)
  1193.         sofprintf(fp,"\t%ld",rrp->ttl);
  1194.     if(rrp->class == CLASS_IN)
  1195.         sofprintf(fp,"\tIN");
  1196.     else
  1197.         sofprintf(fp,"\t<%u>",rrp->class);
  1198.  
  1199.     stuff = dtype(rrp->type);
  1200.     sofprintf(fp,"\t%s",stuff);
  1201.     if(rrp->rdlength == 0){
  1202.         /* Null data portion, indicates nonexistent record */
  1203.         /* or unsupported type.  Hopefully, these will filter */
  1204.         /* as time goes by. */
  1205.         sofprintf(fp,"\n");
  1206.         return;
  1207.     }
  1208.     switch(rrp->type){
  1209.     case TYPE_A:
  1210.         sofprintf(fp,"\t%s\n",inet_ntoa(rrp->rdata.addr));
  1211.         break;
  1212.     case TYPE_CNAME:
  1213.     case TYPE_MB:
  1214.     case TYPE_MG:
  1215.     case TYPE_MR:
  1216.     case TYPE_NS:
  1217.     case TYPE_PTR:
  1218.     case TYPE_TXT:
  1219.         /* These are all printable text strings */
  1220.         sofprintf(fp,"\t%s\n",rrp->rdata.data);
  1221.         break;
  1222.     case TYPE_HINFO:
  1223.         sofprintf(fp,"\t%s\t%s\n",
  1224.          rrp->rdata.hinfo.cpu,
  1225.          rrp->rdata.hinfo.os);
  1226.         break;
  1227.     case TYPE_MX:
  1228.         sofprintf(fp,"\t%u\t%s\n",
  1229.          rrp->rdata.mx.pref,
  1230.          rrp->rdata.mx.exch);
  1231.         break;
  1232.     case TYPE_SOA:
  1233.         sofprintf(fp,"\t%s\t%s\t%lu\t%lu\t%lu\t%lu\t%lu\n",
  1234.          rrp->rdata.soa.mname,rrp->rdata.soa.rname,
  1235.          rrp->rdata.soa.serial,rrp->rdata.soa.refresh,
  1236.          rrp->rdata.soa.retry,rrp->rdata.soa.expire,
  1237.          rrp->rdata.soa.minimum);
  1238.         break;
  1239.     default:
  1240.         sofprintf(fp,"\n");
  1241.         break;
  1242.     }
  1243. }
  1244.  
  1245. /* Search local database for resource records.
  1246.  * Returns RR list, or NULLRR if no record found.
  1247.  */
  1248. static struct rr *
  1249. dfile_search(rrlp, filename)
  1250. struct rr *rrlp;
  1251. char *filename;
  1252. {
  1253.     int counter;
  1254.     register struct rr *frrp;
  1255.     struct rr **rrpp, *result_rrlp, *oldrrp;
  1256.     int32 elapsed;
  1257.     FILE *dbase;
  1258.     struct stat dstat;
  1259.     char *this_dfile;
  1260.  
  1261. #ifdef DEBUG
  1262.     if(Dtrace){
  1263.         tprintf("dfile_search: searching for %s\n",rrlp->name);
  1264.     }
  1265. #endif
  1266.  
  1267. #ifdef DSERVER
  1268.     if (filename)
  1269.         {
  1270.         if(Dtrace) {
  1271.             tprintf("dfile_search: searching local zone file %s\n", filename);
  1272.             }
  1273.         this_dfile = mallocw(strlen(Dzones) + 15);
  1274.         sprintf(this_dfile, "%s/%s", Dzones, filename);
  1275.         }
  1276.     else
  1277. #endif
  1278.         this_dfile = Dfile;
  1279.  
  1280.     while(Dfile_writing > 0)
  1281.         pwait(&Dfile_reading);
  1282.     Dfile_reading++;
  1283.  
  1284.     if((dbase = fopen(this_dfile,READ_TEXT)) == NULLFILE){
  1285.         Dfile_reading--;
  1286.         return NULLRR;
  1287.     }
  1288.     if(fstat(fileno(dbase),&dstat) != 0){
  1289.         tprintf("dfile_search: can't get file status\n");
  1290.         fclose(dbase);
  1291.         Dfile_reading--;
  1292.         return NULLRR;
  1293.     }
  1294.     if((elapsed = (int32)(Dcache_time - (time_t)dstat.st_ctime)) < 0L)
  1295.         elapsed = -elapsed;     /* arbitrary time mismatch */
  1296.  
  1297.     result_rrlp = NULLRR;           /* for contiguous test below */
  1298.     oldrrp = NULLRR;
  1299.     rrpp = &result_rrlp;
  1300.     counter = 0;
  1301.     while((frrp = get_rr(dbase,oldrrp)) != NULLRR){
  1302.         if (++counter == 100)
  1303.             {
  1304.             pwait(NULL);
  1305.             counter = 0;
  1306.             }
  1307.         free_rr(oldrrp);
  1308.         if(frrp->type != TYPE_MISSING
  1309.         && frrp->rdlength > 0
  1310.         && compare_rr_list(rrlp,frrp) == 0){
  1311.             if(frrp->ttl > 0L
  1312.             && (frrp->ttl -= elapsed) <= 0L)
  1313.                 frrp->ttl = 0L;
  1314.             *rrpp = frrp;
  1315.             rrpp = &(*rrpp)->next;
  1316.             oldrrp = copy_rr(frrp);
  1317.         } else {
  1318.             oldrrp = frrp;
  1319.             /*
  1320.                 All records of the same name and the same type
  1321.                 are contiguous.  Therefore, for a single query,
  1322.                 we can stop searching.  Multiple queries must
  1323.                 read the whole file.
  1324.  
  1325.                 Unless we're primary!
  1326.             */
  1327.             if(rrlp->type != TYPE_ANY
  1328.             && rrlp->next == NULLRR
  1329.             && result_rrlp != NULLRR
  1330. #ifdef DSERVER
  1331.             && filename == NULL
  1332. #endif
  1333.             )
  1334.                 break;
  1335.         }
  1336.         if(!main_exit)
  1337.             pwait(NULL);    /* run multiple sessions */
  1338.     }
  1339.     free_rr(oldrrp);
  1340.     *rrpp = NULLRR;
  1341.  
  1342.     fclose(dbase);
  1343.  
  1344.     if(--Dfile_reading <= 0){
  1345.         Dfile_reading = 0;
  1346.         psignal(&Dfile_writing,0);
  1347.     }
  1348.  
  1349. #ifdef DSERVER
  1350.     if (filename)
  1351.         free(this_dfile);
  1352. #endif
  1353.  
  1354.     return result_rrlp;
  1355. }
  1356.  
  1357. /* Process which will add new resource records from the cache
  1358.  * to the local file, eliminating duplicates while it goes.
  1359.  */
  1360. static void __stdargs
  1361. dfile_update(s,unused,p)
  1362. int s;
  1363. void *unused;
  1364. void *p;
  1365. {
  1366.     struct rr **rrpp, *rrlp, *oldrrp;
  1367.     char *newname;
  1368.     FILE *old_fp, *new_fp;
  1369.     struct stat old_stat, new_stat;
  1370.  
  1371.     log(-1,"update Domain.txt initiated");
  1372.  
  1373.     close_s(Curproc->input);
  1374.     usesock(Curproc->input = Cmdpp->input);
  1375.     close_s(Curproc->output);
  1376.     usesock(Curproc->output = Cmdpp->output);
  1377.  
  1378.     newname = strdup(Dfile);
  1379.     strcpy(&newname[strlen(newname)-3],"tmp");
  1380.  
  1381.     while(Dfile_wait_absolute != 0L && !main_exit){
  1382.         register struct rr *frrp;
  1383.         int32 elapsed;
  1384.  
  1385.         while(Dfile_wait_absolute != 0L){
  1386.             elapsed = Dfile_wait_absolute - secclock();
  1387.             Dfile_wait_absolute = 0L;
  1388.             if(elapsed > 0L && !main_exit){
  1389.                 alarm(elapsed*1000L);
  1390.                 pwait(&Dfile_wait_absolute);
  1391.                 alarm(0L);
  1392.             }
  1393.         }
  1394.  
  1395.         log(-1,"update Domain.txt");
  1396.  
  1397.         /* create new file for copy */
  1398.         if((new_fp = fopen(newname,WRITE_TEXT)) == NULLFILE){
  1399.             tprintf("dfile_update: can't create %s!\n",newname);
  1400.             break;
  1401.         }
  1402.         if(fstat(fileno(new_fp),&new_stat) != 0){
  1403.             tprintf("dfile_update: can't get new_file status!\n");
  1404.             fclose(new_fp);
  1405.             break;
  1406.         }
  1407.  
  1408.         pwait(NULL);    /* file operations can be slow */
  1409.  
  1410.         /* timeout the cache one last time before writing */
  1411.         (void)dcache_search(NULLRR);
  1412.  
  1413.         /* copy new RRs out to the new file */
  1414.         /* (can't wait here, the cache might change) */
  1415.         rrpp = &rrlp;
  1416.         for(frrp = Dcache; frrp != NULLRR; frrp = frrp->next ){
  1417.             switch(frrp->source){
  1418.             case RR_QUESTION:
  1419.             case RR_ANSWER:
  1420.             case RR_AUTHORITY:
  1421.             case RR_ADDITIONAL:
  1422.                 *rrpp = copy_rr(frrp);
  1423.                 if(frrp->type != TYPE_MISSING
  1424.                 && frrp->rdlength > 0)
  1425.                     put_rr(new_fp,frrp);
  1426.                 rrpp = &(*rrpp)->next;
  1427.                 frrp->source = RR_FILE;
  1428.                 break;
  1429.             }
  1430.         }
  1431.         *rrpp = NULLRR;
  1432.  
  1433.         /* open up the old file, concurrently with everyone else */
  1434.         if((old_fp = fopen(Dfile,READ_TEXT)) == NULLFILE){
  1435.             /* great! no old file, so we're ready to go. */
  1436.             fclose(new_fp);
  1437.             rename(newname,Dfile);
  1438.             free_rr(rrlp);
  1439.             break;
  1440.         }
  1441.         if(fstat(fileno(old_fp),&old_stat) != 0){
  1442.             tprintf("dfile_update: can't get old_file status!\n");
  1443.             fclose(new_fp);
  1444.             fclose(old_fp);
  1445.             free_rr(rrlp);
  1446.             break;
  1447.         }
  1448.         if((elapsed = (int32)(new_stat.st_ctime - old_stat.st_ctime)) < 0L)
  1449.             elapsed = -elapsed;     /* file times are inconsistant */
  1450.  
  1451.         /* Now append any non-duplicate records */
  1452.         oldrrp = NULLRR;
  1453.         while((frrp = get_rr(old_fp,oldrrp)) != NULLRR){
  1454.             free_rr(oldrrp);
  1455.             if(frrp->name == NULLCHAR
  1456.             && frrp->comment != NULLCHAR)
  1457.                 put_rr(new_fp,frrp);
  1458.             if(frrp->type != TYPE_MISSING
  1459.             && frrp->rdlength > 0
  1460.             && compare_rr_list(rrlp,frrp) != 0){
  1461.                 if(frrp->ttl > 0L
  1462.                 && (frrp->ttl -= elapsed) <= 0L)
  1463.                     frrp->ttl = 0L;
  1464.                 if(frrp->ttl != 0 || !Dfile_clean)
  1465.                     put_rr(new_fp,frrp);
  1466.             }
  1467.             oldrrp = frrp;
  1468.             if(!main_exit)
  1469.                 pwait(NULL);    /* run in background */
  1470.         }
  1471.         free_rr(oldrrp);
  1472.         fclose(new_fp);
  1473.         fclose(old_fp);
  1474.         free_rr(rrlp);
  1475.  
  1476.         /* wait for everyone else to finish reading */
  1477.         Dfile_writing++;
  1478.         while(Dfile_reading > 0)
  1479.             pwait(&Dfile_writing);
  1480.  
  1481.         unlink(Dfile);
  1482.         rename(newname,Dfile);
  1483.  
  1484.         Dfile_writing = 0;
  1485.         psignal(&Dfile_reading,0);
  1486.     }
  1487.     free(newname);
  1488.  
  1489.     log(-1,"update Domain.txt finished");
  1490.     Dfile_updater = NULLPROC;
  1491. }
  1492.  
  1493.  
  1494. /**
  1495.  **     Domain Server Utilities
  1496.  **/
  1497.  
  1498. static void
  1499. dumpdomain(dhp,rtt)
  1500. struct dhdr *dhp;
  1501. int32 rtt;
  1502. {
  1503.     struct rr *rrp;
  1504.     char * stuff;
  1505.  
  1506.     tprintf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
  1507.      dhp->id,(long)rtt / 1000L,
  1508.      dhp->qr,dhp->opcode,dhp->aa,dhp->tc,dhp->rd,
  1509.      dhp->ra,dhp->rcode);
  1510.     tprintf("%u questions:\n",dhp->qdcount);
  1511.     for(rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next){
  1512.         stuff = dtype(rrp->type);
  1513.         tprintf("%s type %s class %u\n",rrp->name,
  1514.          stuff,rrp->class);
  1515.     }
  1516.     tprintf("%u answers:\n",dhp->ancount);
  1517.     for(rrp = dhp->answers; rrp != NULLRR; rrp = rrp->next){
  1518.         put_rr(stdout,rrp);
  1519.     }
  1520.     tprintf("%u authority:\n",dhp->nscount);
  1521.     for(rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next){
  1522.         put_rr(stdout,rrp);
  1523.     }
  1524.     tprintf("%u additional:\n",dhp->arcount);
  1525.     for(rrp = dhp->additional; rrp != NULLRR; rrp = rrp->next){
  1526.         put_rr(stdout,rrp);
  1527.     }
  1528.     fflush(stdout);
  1529. }
  1530.  
  1531. static int
  1532. dns_makequery(
  1533.     int16 op,               /* operation */
  1534.     struct rr *srrp,        /* Search RR */
  1535.     char *buffer,           /* Area for query */
  1536.     int16 buflen)           /* Length of same */
  1537. {
  1538.     char *cp,*cp1;
  1539.     char *dname, *sname;
  1540.     int16 parameter;
  1541.     int16 dlen,len;
  1542.  
  1543.     cp = buffer;
  1544.     /* Use millisecond clock for timestamping */
  1545.     cp = put16(cp,(int16)msclock());
  1546.     parameter = (op << 11)
  1547.             | 0x0100;       /* Recursion desired */
  1548.     cp = put16(cp,parameter);
  1549.     cp = put16(cp,1);
  1550.     cp = put16(cp,0);
  1551.     cp = put16(cp,0);
  1552.     cp = put16(cp,0);
  1553.  
  1554.     sname = strdup(srrp->name);
  1555.     dname = sname;
  1556.     dlen = strlen(dname);
  1557.     for(;;){
  1558.         /* Look for next dot */
  1559.         cp1 = strchr(dname,'.');
  1560.         if(cp1 != NULLCHAR)
  1561.             len = cp1-dname;        /* More to come */
  1562.         else
  1563.             len = dlen;     /* Last component */
  1564.         *cp++ = len;            /* Write length of component */
  1565.         if(len == 0)
  1566.             break;
  1567.         /* Copy component up to (but not including) dot */
  1568.         strncpy(cp,dname,len);
  1569.         cp += len;
  1570.         if(cp1 == NULLCHAR){
  1571.             *cp++ = 0;      /* Last one; write null and finish */
  1572.             break;
  1573.         }
  1574.         dname += len+1;
  1575.         dlen -= len+1;
  1576.     }
  1577.     free(sname);
  1578.     cp = put16(cp,srrp->type);
  1579.     cp = put16(cp,srrp->class);
  1580.     return (int) (cp - buffer);
  1581. }
  1582.  
  1583. /* domain server resolution loop
  1584.  * returns: any answers in cache.
  1585.  *      (future features)
  1586.  *      multiple queries.
  1587.  *      inverse queries.
  1588.  */
  1589. static void
  1590. dns_query(rrlp)
  1591. struct rr *rrlp;
  1592. {
  1593.     struct mbuf *bp;
  1594.     struct dhdr *dhp;
  1595.     struct dserver *dp;     /* server list */
  1596.     int32 rtt,abserr;
  1597.     int tried = 0;          /* server list has been retried (count) */
  1598.  
  1599.     if((dp = Dservers) == NULLDOM){
  1600.         return;
  1601.     }
  1602.  
  1603.     for(;;){
  1604.         char *buf;
  1605.         int len;
  1606.         struct sockaddr_in server_in;
  1607.         int s;
  1608.         int rval;
  1609.  
  1610.         dp->queries++;
  1611.  
  1612.         s = socket(AF_INET,SOCK_DGRAM,0);
  1613.         server_in.sin_family = AF_INET;
  1614.         server_in.sin_port = IPPORT_DOMAIN;
  1615.         server_in.sin_addr.s_addr = dp->address;
  1616.  
  1617.         if(Dtrace){
  1618.             tprintf("dns_query: querying server %s for %s\n",
  1619.              inet_ntoa(dp->address),rrlp->name);
  1620.         }
  1621.  
  1622.         buf = mallocw(512);
  1623.         len = dns_makequery(0,rrlp,buf,512);
  1624.         sendto(s,buf,len,0,(char *)&server_in,sizeof(server_in));
  1625.         free(buf);
  1626.         alarm(max(dp->timeout,100));
  1627.         /* Wait for something to happen */
  1628.         rval = recv_mbuf(s,&bp,0,NULLCHAR,0);
  1629.         alarm(0L);
  1630.         close_s(s);
  1631.  
  1632.         if(Dtrace){
  1633.             tprintf("dns_query: received message length %d, errno %d\n", rval, errno );
  1634.         }
  1635.  
  1636.         if(rval > 0)
  1637.             break;
  1638.  
  1639.         if(errno == EABORT){
  1640.             return;         /* Killed by "reset" command */
  1641.         }
  1642.  
  1643.         /* Timeout; back off this one and try another server */
  1644.         dp->timeouts++;
  1645.         dp->timeout <<= 1;
  1646.         /* There may be a limit to how long we will wait */
  1647.         if(Dserver_maxwait && dp->timeout > (Dserver_maxwait * 1000L))
  1648.                                         dp->timeout = Dserver_maxwait * 1000L;
  1649.  
  1650.         if((dp = dp->next) == NULLDOM){
  1651.             dp = Dservers;
  1652.             if(Dserver_retries > 0 && ++tried > Dserver_retries)
  1653.                 {
  1654.                 if (Dserver_maxwait == 0)
  1655.                     /* Only if not specified the maximum wait - MT Oct 92 */
  1656.                     {
  1657.                     /* Reset timeouts  - GT 07 Jun 92. */
  1658.                     while (dp != NULLDOM)
  1659.                         {
  1660.                         dp->timeout = 2 * dp->mdev + dp->srtt + 3;
  1661.                         dp = dp->next;
  1662.                         }
  1663.                     }       
  1664.                 dp = Dservers;
  1665.                 return;
  1666.                 }
  1667.         }
  1668.     }
  1669.  
  1670.     /* got a response */
  1671.     dp->responses++;
  1672.     dhp = (struct dhdr *) mallocw(sizeof(struct dhdr));
  1673.     ntohdomain(dhp,&bp);    /* Convert to local format */
  1674.  
  1675.     /* Compute and update the round trip time */
  1676.     rtt = (int32) ((int16)msclock() - dhp->id);
  1677.     abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
  1678.     dp->srtt = ((AGAIN-1) * dp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
  1679.     dp->mdev = ((DGAIN-1) * dp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
  1680.     dp->timeout = 4 * dp->mdev + dp->srtt;
  1681.  
  1682.     /* move to top of list for next time */
  1683.     if(dp->prev != NULLDOM){
  1684.         dlist_drop(dp);
  1685.         dlist_add(dp);
  1686.     }
  1687.  
  1688.     if(Dtrace)
  1689.         dumpdomain(dhp,rtt);
  1690.  
  1691.     /* Add negative reply to answers.  This assumes that there was
  1692.      * only one question, which is true for all questions we send.
  1693.      */
  1694.     if(dhp->aa && (dhp->rcode == NAME_ERROR || dhp->ancount == 0)){
  1695.         register struct rr *rrp;
  1696.         long ttl = 600L; /* Default TTL for negative records */
  1697.  
  1698.         /* look for SOA ttl */
  1699.         for(rrp = dhp->authority; rrp != NULLRR; rrp = rrp->next){
  1700.             if(rrp->type == TYPE_SOA)
  1701.                 ttl = rrp->ttl;
  1702.         }
  1703.  
  1704.         /* make the questions the negative answers */
  1705.         for(rrp = dhp->questions; rrp != NULLRR; rrp = rrp->next)
  1706.             rrp->ttl = ttl;
  1707.     } else {
  1708.         free_rr(dhp->questions);
  1709.         dhp->questions = NULLRR;
  1710.     }
  1711.  
  1712.     /* post in reverse order to maintain original order */
  1713.     dcache_update(dhp->additional);
  1714.     dcache_update(dhp->authority);
  1715.     dcache_update(dhp->answers);
  1716.     dcache_update(dhp->questions);
  1717.  
  1718.     Dfile_wait_absolute = secclock() + Dfile_wait_relative;
  1719.     if(Dfile_updater == NULLPROC){
  1720.         Dfile_updater = newproc("domain update",
  1721.             512,dfile_update,0,NULL,NULL,0);
  1722.     }
  1723.  
  1724. #ifdef DEBUG
  1725.     if(Dtrace)
  1726.         keywait(NULLCHAR,1);    /* so we can look around */
  1727. #endif
  1728.     free((char *)dhp);
  1729.     return;
  1730. }
  1731.  
  1732.  
  1733. /**
  1734.  **     Resolver Utilities
  1735.  **/
  1736.  
  1737. /* Return TRUE if string appears to be an IP address in dotted decimal;
  1738.  * return FALSE otherwise (i.e., if string is a domain name)
  1739.  */
  1740. static int
  1741. isaddr(s)
  1742. register char *s;
  1743. {
  1744.     char c;
  1745.  
  1746.     if(s == NULLCHAR)
  1747.         return TRUE;    /* Can't happen */
  1748.  
  1749.     while((c = *s++) != '\0'){
  1750.         if(c != '[' && c != ']' && !isdigit(c) && c != '.')
  1751.             return FALSE;
  1752.     }
  1753.     return TRUE;
  1754. }
  1755.  
  1756. /* Return "normalized" domain name, with default suffix and trailing '.'
  1757.  */
  1758. static char *
  1759. checksuffix(dname)
  1760. char *dname;
  1761. {
  1762.     char *sname, *tname;
  1763.  
  1764.     sname = strdup(dname);
  1765.     if(strchr(sname,'.') == NULLCHAR && Dsuffix != NULLCHAR){
  1766.         /* Append default suffix */
  1767.         tname = mallocw(strlen(sname)+strlen(Dsuffix)+2);
  1768.         sprintf(tname,"%s.%s",sname,Dsuffix);
  1769.         free(sname);
  1770.         sname = tname;
  1771.     }
  1772.     if(sname[strlen(sname)-1] != '.'){
  1773.         /* Append trailing dot */
  1774.         tname = mallocw(strlen(sname)+2);
  1775.         sprintf(tname,"%s.",sname);
  1776.         free(sname);
  1777.         sname = tname;
  1778.     }
  1779.     return sname;
  1780. }
  1781.  
  1782. #ifdef DSERVER
  1783.  
  1784. char *zone_filename(char *domain, int32 *expire)
  1785. {
  1786.     struct DOM_FILE *t_dom_file;
  1787.     char *name;
  1788.     int len;
  1789.     len = strlen(domain);
  1790.     name = mallocw(len + 2);
  1791.     strcpy(name, domain);
  1792.     if (name[len - 1] != '.')
  1793.         {
  1794.         strcat(name, ".");
  1795.         len++;
  1796.         }
  1797.     t_dom_file = dom_file;
  1798.     while (Drx != NULLPROC && t_dom_file)
  1799.         {
  1800.         if (stricmp(t_dom_file->domain, name + len
  1801.                                         - strlen(t_dom_file->domain)) == 0)
  1802.             {
  1803.             if (expire)
  1804.                 *expire = t_dom_file->dom_soa.expire;
  1805.             if (Dtrace)
  1806.                 tprintf("DNS: Using file %s\n", t_dom_file->filename);
  1807.             free(name);
  1808.             return t_dom_file->filename;
  1809.             }
  1810.         t_dom_file = t_dom_file->next;
  1811.         }
  1812.     free(name);
  1813.     return NULL;
  1814. }
  1815.  
  1816. #endif
  1817.  
  1818. /*
  1819.     resolver - Search for resource records.
  1820.               Returns RR list, or NULLRR if no record found.
  1821. */
  1822.  
  1823. static struct rr *resolver(struct rr *rrlp)
  1824. {
  1825.     struct rr *result_rrlp;
  1826. #ifdef DSERVER
  1827.     char *t;
  1828.     int32 expire;
  1829.     struct rr *t_rr;
  1830. #endif
  1831.  
  1832. #ifdef DSERVER
  1833.     /*
  1834.     Are we primary for the domain? If so, we must answer from the
  1835.     file cos we can't guarantee that a full set of records for a
  1836.     particular query will be in the cache.
  1837.     */
  1838.     if ((t = zone_filename(rrlp->name, &expire)) != NULL)
  1839.         {
  1840.         result_rrlp = dfile_search(rrlp, t);
  1841.         if (result_rrlp != NULLRR)
  1842.             {
  1843.             t_rr = result_rrlp;
  1844.             while (t_rr)
  1845.                 {
  1846.                 t_rr->ttl = expire;
  1847.                 t_rr = t_rr->next;
  1848.                 }
  1849. /*
  1850. If we never use the cache to answer things we're primary for then there's
  1851. no point in caching the results! MT - G7LEU
  1852.             dcache_add(copy_rr_list(result_rrlp));
  1853. */
  1854.             }
  1855.         return result_rrlp;
  1856.         }
  1857. #endif
  1858.  
  1859.     if((result_rrlp = dcache_search(rrlp)) == NULLRR){
  1860.         result_rrlp = dfile_search(rrlp, NULL);
  1861.     }
  1862.     if(result_rrlp == NULLRR || check_ttl(result_rrlp) != 0){
  1863.         dcache_add(result_rrlp);        /* save any expired RRs */
  1864.         dns_query(rrlp);
  1865.         result_rrlp = dcache_search(rrlp);
  1866.     }
  1867.     dcache_add(copy_rr_list(result_rrlp));
  1868.     return result_rrlp;
  1869. }
  1870.  
  1871. /* general entry point for address -> domain name resolution.
  1872.  * Returns RR list, or NULLRR if no record found.
  1873.  */
  1874. struct rr *
  1875. inverse_a(ip_address)
  1876. int32 ip_address;
  1877. {
  1878.     struct rr *prrp;
  1879.     struct rr *result_rrlp;
  1880.     char pname[30];
  1881.  
  1882.     if(ip_address == 0L)
  1883.         return NULLRR;
  1884.  
  1885.     sprintf( pname, "%u.%u.%u.%u.IN-ADDR.ARPA.",
  1886.             lobyte(loword(ip_address)),
  1887.             hibyte(loword(ip_address)),
  1888.             lobyte(hiword(ip_address)),
  1889.             hibyte(hiword(ip_address)) );
  1890.  
  1891.     prrp = make_rr(RR_QUERY,pname,CLASS_IN,TYPE_PTR,0,0,NULL);
  1892.  
  1893.     prrp->next =            /* make list to speed search */
  1894.         make_rr(RR_INQUERY,NULLCHAR,CLASS_IN,TYPE_A,0,4,&ip_address);
  1895.  
  1896.     result_rrlp = resolver(prrp);
  1897.  
  1898.     free_rr(prrp);
  1899.     return result_rrlp;
  1900. }
  1901.  
  1902. /* general entry point for domain name -> resource resolution.
  1903.  * Returns RR list, or NULLRR if no record found.
  1904.  */
  1905. struct rr *
  1906. resolve_rr(
  1907.     char *dname,
  1908.     int16 dtype)
  1909. {
  1910.     struct rr *qrrp;
  1911.     struct rr *result_rrlp;
  1912.     char *sname;
  1913.     int looping = MAXCNAME;
  1914.  
  1915.     if(dname == NULLCHAR)
  1916.         return NULLRR;
  1917.  
  1918.     sname = checksuffix(dname);
  1919.     qrrp = make_rr(RR_QUERY,sname,CLASS_IN,dtype,0,0,NULL);
  1920.     free(sname);
  1921.  
  1922.     while(looping > 0){
  1923.  
  1924.         /* Change this condition to include TYPE_ANY. ILP 17/2/93 */
  1925.  
  1926.         if((result_rrlp=resolver(qrrp)) == NULLRR
  1927.         || result_rrlp->type == dtype
  1928.         || dtype == TYPE_ANY)
  1929.             break;
  1930. #ifdef DEBUG
  1931.         if(Dtrace)
  1932.             put_rr(stdout,result_rrlp);
  1933. #endif
  1934.         /* Should be CNAME or PTR record */
  1935.         /* Replace name and try again */
  1936.         free(qrrp->name);
  1937.         qrrp->name = strdup(result_rrlp->rdata.name);
  1938.         free_rr(result_rrlp);
  1939.         result_rrlp = NULLRR;
  1940.         looping--;
  1941.     }
  1942.     free_rr(qrrp);
  1943.     return result_rrlp;
  1944. }
  1945.  
  1946. /* main entry point for address -> domain name resolution.
  1947.  * Returns string, or NULLCHAR if no name found.
  1948.  */
  1949. char *
  1950. resolve_a(ip_address,shorten)
  1951. int32 ip_address;               /* search address */
  1952. int shorten;                    /* return only first part of name (flag)*/
  1953. {
  1954.     struct rr *save_rrlp, *rrlp;
  1955.     char *result = NULLCHAR;
  1956.  
  1957.     for( rrlp = save_rrlp = inverse_a(ip_address);
  1958.          rrlp != NULLRR && result == NULLCHAR;
  1959.          rrlp = rrlp->next ){
  1960.         if(rrlp->rdlength > 0){
  1961.             switch(rrlp->type){
  1962.             case TYPE_PTR:
  1963.                 result = strdup(rrlp->rdata.name);
  1964.                 break;
  1965.             case TYPE_A:
  1966.                 result = strdup(rrlp->name);
  1967.                 break;
  1968.             }
  1969.         }
  1970.     }
  1971.     free_rr(save_rrlp);
  1972.  
  1973.     if(result != NULLCHAR && shorten){
  1974.         int dot;
  1975.         char *shortened;
  1976.  
  1977.         if((dot = strcspn(result, ".")) == 0){
  1978.             shortened = mallocw(dot+1);
  1979.             strncpy(shortened, result, dot);
  1980.             shortened[dot] = '\0';
  1981.             free(result);
  1982.             result = shortened;
  1983.         }
  1984.     }
  1985.     return result;
  1986. }
  1987.  
  1988. /* Main entry point for domain name -> address resolution.
  1989.  * Returns 0 if name is currently unresolvable.
  1990.  */
  1991. int32
  1992. resolve(name)
  1993. char *name;
  1994. {
  1995.     register struct rr *rrlp;
  1996.     int32 ip_address = 0;
  1997.  
  1998.     if(name == NULLCHAR)
  1999.         return 0;
  2000.  
  2001.     if(isaddr(name))
  2002.         return aton(name);
  2003.  
  2004.     if((rrlp = resolve_rr(name,TYPE_A)) != NULLRR
  2005.      && rrlp->rdlength > 0)
  2006.         ip_address = rrlp->rdata.addr;
  2007.  
  2008.     /* multi-homed hosts are handled here */
  2009.     if(rrlp != NULLRR && rrlp->next != NULLRR) {
  2010.         register struct rr *rrp;
  2011.         register struct route *rp;
  2012.         int16 cost = MAXINT16;
  2013.         rrp = rrlp;
  2014.         /* choose the best of a set of routes */
  2015.         while(rrp != NULLRR) {
  2016.             if(rrp->rdlength > 0
  2017.              && (rp = rt_lookup(rrp->rdata.addr)) != NULLROUTE
  2018. #if    0
  2019.              && rp->metric <= cost) {
  2020. #endif
  2021.              && rp->metric < cost) {
  2022.                 ip_address = rrp->rdata.addr;
  2023.                 cost = rp->metric;
  2024.             }
  2025.             rrp = rrp->next;
  2026.         }
  2027.     }
  2028.  
  2029.     free_rr(rrlp);
  2030.     return ip_address;
  2031. }
  2032.  
  2033.  
  2034. /* Main entry point for MX record lookup.
  2035.  * Returns 0 if name is currently unresolvable.
  2036.  */
  2037. int32
  2038. resolve_mx(name)
  2039. char *name;
  2040. {
  2041.     register struct rr *rrp, *arrp;
  2042.     char *sname, *tmp, *cp;
  2043.     int32 addr, ip_address = 0;
  2044.     int16 pref = MAXINT16;
  2045.     int our_domain = 0;
  2046.  
  2047.     are_we_an_mx = 0;
  2048.  
  2049. #ifdef DSERVER
  2050.     if (zone_filename(name, NULL))
  2051.         our_domain = 1;
  2052. #endif
  2053.  
  2054.     if(name == NULLCHAR)
  2055.         return 0;
  2056.  
  2057.     if(isaddr(name)){
  2058.         if((sname = resolve_a(aton(name),FALSE)) == NULLCHAR)
  2059.             return 0;
  2060.     }
  2061.     else
  2062.         sname = strdup(name);
  2063.  
  2064.     cp = sname;
  2065.     while(1){
  2066.         rrp = arrp = resolve_rr(sname,TYPE_MX);
  2067.         /* Search this list of rr's for an MX record */
  2068.         while(rrp != NULLRR){
  2069.             if(rrp->rdlength > 0 && (addr = resolve(rrp->rdata.mx.exch)) != 0L)
  2070.                 {
  2071.                 if (addr == Ip_addr)
  2072.                     are_we_an_mx = 1;
  2073.                 if (rrp->rdata.mx.pref <= pref)
  2074.                     {
  2075.                     pref = rrp->rdata.mx.pref;
  2076.                     ip_address = addr;
  2077.                     }
  2078.                 }
  2079.             rrp = rrp->next;
  2080.         }
  2081.         free_rr(arrp);
  2082.         if(ip_address != 0)
  2083.             break;
  2084.         /* If this is our domain we can say no at this point */
  2085.         if (our_domain)
  2086.             break;
  2087.         /* Compose wild card one level up */
  2088.         if((cp = strchr(cp,'.')) == NULLCHAR)
  2089.             break;
  2090.         tmp = mallocw(strlen(cp)+2);
  2091.         sprintf(tmp,"*%s",cp);          /* wildcard expansion */
  2092.         free(sname);
  2093.         sname = tmp;
  2094.         cp = sname + 2;
  2095.     }
  2096.     free(sname);
  2097.     if (Dtrace)
  2098.         tprintf("resolve_mx %s returns %s\n", name, inet_ntoa(ip_address));
  2099.     return ip_address;
  2100. }
  2101.  
  2102. /* Search for local records of the MB, MG and MR type. Returns list of
  2103.  * matching records.
  2104.  */
  2105. struct rr *
  2106. resolve_mailb(name)
  2107. char *name;             /* local username, without trailing dot */
  2108. {
  2109.     register struct rr *result_rrlp;
  2110.     struct rr *rrlp;
  2111.     char *sname;
  2112.  
  2113.     /* Append trailing dot */
  2114.     sname = mallocw(strlen(name)+2);
  2115.     sprintf(sname,"%s.",name);
  2116.     rrlp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MB,0,0,NULL);
  2117.     rrlp->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MG,0,0,NULL);
  2118.     rrlp->next->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MR,0,0,NULL);
  2119.     free(sname);
  2120.     if((result_rrlp = dcache_search(rrlp)) == NULLRR){
  2121.         result_rrlp = dfile_search(rrlp, NULL);
  2122.     }
  2123.     free_rr(rrlp);
  2124.     if(Dsuffix != NULLCHAR){
  2125.         rrlp = result_rrlp;
  2126.         while(rrlp != NULLRR){  /* add domain suffix to data */
  2127.             if(rrlp->rdlength > 0 &&
  2128.                rrlp->rdata.name[rrlp->rdlength-1] != '.'){
  2129.                 sname = mallocw(rrlp->rdlength +
  2130.                     strlen(Dsuffix)+2);
  2131.                 sprintf(sname,"%s.%s",rrlp->rdata.name,Dsuffix);
  2132.                 free(rrlp->rdata.name);
  2133.                 rrlp->rdata.name = sname;
  2134.                 rrlp->rdlength = strlen(sname);
  2135.             }
  2136.             rrlp = rrlp->next;
  2137.         }
  2138.     }
  2139.     dcache_add(copy_rr_list(result_rrlp));
  2140.     return result_rrlp;
  2141. }
  2142.  
  2143. #ifdef DSERVER
  2144.  
  2145. /* Domain Name Server - based on the server in GRI-Nos 910828
  2146.  * ported to current NOS code by Johan. K. Reinalda, WG7J/PA3DIS
  2147.  * Merged into Demon Internet Services version - MT (g7leu) Sept 1992.
  2148.  * Added primary nameserver - MT (g7leu) October 1992.
  2149.  */
  2150.  
  2151. /* Process a query received by the DNS server */
  2152. static void __stdargs
  2153. proc_query(unused,d,b)
  2154. int unused;
  2155. void *d;
  2156. void *b;
  2157. {
  2158.     struct dserver *dp;
  2159.     struct dhdr *dhdr;
  2160.     int i,len;
  2161.     char *buf;
  2162.     struct sockaddr_in server;
  2163.     struct rr *rrp, *rrans, *rrtmp;
  2164. #ifdef    notdef
  2165.     struct rr *rrns, *rradd, *ap;
  2166. #endif
  2167.     struct rr *qp;
  2168.     int32 expire;
  2169.  
  2170.     dp = (struct dserver *) d;      /* The query address */
  2171.     dhdr = (struct dhdr *) b;       /* The query in host format */
  2172.  
  2173.     rrans = NULLRR;
  2174. #ifdef notdef
  2175.     rrns = rradd = NULLRR;
  2176. #endif
  2177.     qp = dhdr->questions;
  2178.  
  2179.     /* This loop does NOT support multiple questions yet */
  2180. #ifdef notdef
  2181.     for(i=0;i<dhdr->qdcount;i++){
  2182. #endif
  2183.  
  2184.     if(zone_filename(qp->name, &expire))
  2185.         dhdr->aa = 1;
  2186.     else dhdr->aa = 0;
  2187.  
  2188.     switch(qp->type) {
  2189.     case TYPE_A:
  2190.     case TYPE_MX:
  2191.     case TYPE_CNAME:
  2192.     case TYPE_HINFO:
  2193.     case TYPE_PTR:
  2194.     case TYPE_NS:
  2195.     case TYPE_SOA:
  2196.  
  2197.         /* So we can do a dom q <dom.name> from another ka9q ILP 17/2/93 */
  2198.     case TYPE_ANY:
  2199.  
  2200.       /* Not all of the below types are implemented in resolve_rr() */
  2201. #ifdef notdef
  2202.     case TYPE_TXT:
  2203. #endif
  2204.         if((rrp = resolve_rr(qp->name,qp->type)) != NULLRR) {
  2205.         /* we found an entry, go tell him */
  2206.         dhdr->rcode = NO_ERROR;
  2207.         dhdr->qr = RESPONSE;
  2208.                 rrp->ttl = expire;
  2209.         } else {
  2210.         /* we did not find an entry, go tell him */
  2211.         rrp = (struct rr *)callocw(1,sizeof(struct rr));
  2212.         rrp->name = strdup(qp->name);
  2213.         rrp->type = qp->type;
  2214.         rrp->class = qp->class;
  2215.         rrp->ttl = 500L;
  2216.         rrp->rdata.addr = 0L;
  2217.         rrp->rdlength = 4;  /* size of addr data */
  2218.         dhdr->rcode = NAME_ERROR;
  2219.         dhdr->qr = RESPONSE;
  2220.         }
  2221.         rrans = rrp;
  2222.         break;
  2223.     /* Search only the local cache and domain file for these next few */
  2224.     /* Is this a good idea ??? */
  2225.     case TYPE_MB:
  2226.     case TYPE_MG:
  2227.     case TYPE_MR:
  2228.         rrp = make_rr(RR_QUERY,qp->name,CLASS_IN,qp->type,0,0,NULL);
  2229.         if((rrans = dcache_search(rrp)) == NULLRR){
  2230.         rrans = dfile_search(rrp, NULL);
  2231.         }
  2232.         free_rr(rrp);
  2233.         break;
  2234. #ifdef notdef
  2235.     /* Not implemented, yet (?) */
  2236.     case TYPE_MD:
  2237.     case TYPE_MF:
  2238.     case TYPE_WKS:
  2239.     case TYPE_NULL:
  2240.     case TYPE_MINFO:
  2241. #endif
  2242.     default:
  2243.         dhdr->rcode = NOT_IMPL;
  2244.         dhdr->qr = RESPONSE;
  2245.     }
  2246.     /* This loop does NOT support multiple questions yet */
  2247. #ifdef notdef
  2248.     qp = qp->next;  /* next question */
  2249.     }
  2250. #endif
  2251.  
  2252.     /* Find the number of answer records */
  2253.     i = 0;
  2254.     rrtmp = rrans;
  2255.     while(rrtmp != NULLRR) {
  2256.     i++;
  2257.     rrtmp = rrtmp->next;
  2258.     }
  2259.     dhdr->ancount = i;
  2260.     dhdr->answers = rrans;
  2261.  
  2262.     /* Authority & Additional RR's not implemented yet. */
  2263.     dhdr->authority = NULLRR;
  2264.     dhdr->nscount = 0;
  2265.     dhdr->arcount = 0;
  2266.     dhdr->additional = NULLRR;
  2267.  
  2268. #ifdef notdef
  2269.     /* Find the number of authority records */
  2270.     i = 0;
  2271.     rrtmp = rrns;
  2272.     while(rrtmp != NULLRR) {
  2273.     i++;
  2274.     rrtmp = rrtmp->next;
  2275.     }
  2276.     dhdr->nscount = i;
  2277.     dhdr->authority = rrns;
  2278.  
  2279.     /* Find the number of additional records */
  2280.     i = 0;
  2281.     rrtmp = rradd;
  2282.     while(rrtmp != NULLRR) {
  2283.     i++;
  2284.     rrtmp = rrtmp->next;
  2285.     }
  2286.     dhdr->arcount = i;
  2287.     dhdr->additional = rradd;
  2288. #endif
  2289.  
  2290.     if(Dtrace) {
  2291.     tputs("DNS: replying");
  2292.     dumpdomain(dhdr,0);
  2293.     }
  2294.  
  2295.     /* Maximum reply size is 512, see rfc1034/1035 */
  2296.     buf = mallocw(512);
  2297.     len = htondomain(dhdr,buf,512);
  2298.     free_dhdr(dhdr);
  2299.  
  2300.     server.sin_family = AF_INET;
  2301.     server.sin_port = dp->port;
  2302.     server.sin_addr.s_addr = dp->address;
  2303.     sendto(Dsocket,buf,len,0,(char *)&server,sizeof(server));
  2304.     free(buf);
  2305.     free((char *)dp);
  2306. }
  2307.  
  2308.  
  2309. /* Process to receive all domain server related messages */
  2310. static void __stdargs
  2311. drx(unused,u,p)
  2312. int unused;
  2313. void *u;
  2314. void *p;
  2315. {
  2316.     struct sockaddr_in sock,from;
  2317.     int fromlen;
  2318.     struct mbuf *bp;
  2319.     struct dhdr *dhdr;
  2320.     struct dserver *dp;
  2321.     int foo;
  2322.  
  2323.     Dsocket = socket(AF_INET,SOCK_DGRAM,0);
  2324.     sock.sin_family = AF_INET;
  2325.     sock.sin_addr.s_addr = INADDR_ANY;
  2326.     sock.sin_port = IPPORT_DOMAIN;
  2327.     if(bind(Dsocket,(char *)&sock,sizeof(sock)) == -1) {
  2328.     tputs("DNS: can't bind\n");
  2329.         Drx = NULLPROC;
  2330.         return;
  2331.     }
  2332.     /* Now loop forever, processing queries */
  2333.     for(;;){
  2334.         fromlen = sizeof(from);
  2335.     if((foo = recv_mbuf(Dsocket,&bp,0,(char *)&from,&fromlen)) == -1)
  2336.         break;  /* Server closing */
  2337.         if(foo == 0)
  2338.             continue;
  2339.         dhdr = mallocw(sizeof(struct dhdr));
  2340.         ntohdomain(dhdr,&bp);
  2341.     if(Dtrace) {
  2342.         tprintf("DNS: %u bytes from %s\n",foo,
  2343.         psocket((struct sockaddr *)&from));
  2344.         dumpdomain(dhdr,0);
  2345.     }
  2346.     /* Process queries only */
  2347.     if(dhdr->qr == QUERY) {
  2348.         /* Queries from ourself will cause a loop ! */
  2349.         if(ismyaddr(from.sin_addr.s_addr) != NULLIF) {
  2350.         if(Dtrace)
  2351.             tputs("DNS: question from myself ignored\n");
  2352.         free_dhdr(dhdr);
  2353.         continue;
  2354.         } else {
  2355.         dp=(struct dserver *)callocw(1,sizeof(struct dserver));
  2356.         dp->address = from.sin_addr.s_addr;
  2357.         dp->srtt = (Dserver_maxwait * 1000L) / MSPTICK;
  2358.         dp->timeout = dp->srtt * 2;
  2359.         dp->port = from.sin_port;
  2360.         if(dhdr->opcode == ZONEINIT) {
  2361.             /* ZONEINIT not implemented */
  2362.             free_dhdr(dhdr);
  2363.             free(dp);
  2364.          } else
  2365.             newproc("Domain server",1024,proc_query
  2366.                 ,0,(void *)dp,(void *)dhdr,0);
  2367.             }
  2368.         }
  2369.     }
  2370. }
  2371.                 
  2372. static int
  2373. dodnsserver(argc,argv,p)
  2374. int argc;
  2375. char *argv[];
  2376. void *p;
  2377. {
  2378.     struct DOM_FILE *t_dom_file;
  2379.     FILE *fp, *bfp;
  2380.     char *t, *t1, *t2,*t3, *t4;
  2381.     int done;
  2382.     int32 source;
  2383.     struct rr *frrp, *oldrrp;
  2384. #if    0
  2385.     struct soa *soap;
  2386. #endif
  2387.     char type, *delim = " \t";
  2388.     if(Drx == NULLPROC)
  2389.         {
  2390.         /* Get rid of any old data */
  2391.         t_dom_file = dom_file;
  2392.         while (t_dom_file)
  2393.             {
  2394.             free(t_dom_file->filename);
  2395.             free(t_dom_file->domain);
  2396.             free(t_dom_file);
  2397.             t_dom_file = t_dom_file->next;
  2398.             }
  2399.         dom_file = NULL;
  2400.         /*
  2401.         Find out where we're primary for (if anywhere)
  2402.         */
  2403.         t = mallocw(200);
  2404.         t2 = mallocw(200);
  2405.         t4 = mallocw(13);
  2406.         bfp = fopen(Dboot, READ_TEXT);
  2407.         if (bfp)
  2408.             while (1)
  2409.                 {
  2410.                 if (feof(bfp) || !fgets(t, 199, bfp))
  2411.                     {
  2412.                     fclose(bfp);
  2413.                     break;
  2414.                     }
  2415.                 t1 = strtok(t, delim);
  2416.                 if (!t1)
  2417.                     continue;
  2418.                 source = 0;
  2419.                 type = '0';
  2420.                 if (stricmp(t1, "primary") == 0)
  2421.                     type = '1';
  2422.                 if (stricmp(t1, "secondary") == 0)
  2423.                     type = '2';
  2424.                 if (type == '0')
  2425.                     continue;
  2426.                 t1 = strtok(NULL, delim);
  2427.                 if (!t1)
  2428.                     continue;
  2429.                 strlwr(t1);
  2430.                 strcpy(t2, t1);
  2431.                 t1 = strtok(NULL, delim);
  2432.                 if (!t1)
  2433.                     continue;
  2434.                 if (type == '2')
  2435.                     {
  2436.                     source = resolve(t1);
  2437.                     t1 = strtok(NULL, delim);
  2438.                     if (!t1)
  2439.                         continue;
  2440.                     }
  2441.                 rip(t1);
  2442.                 strcpy(t4, t1);
  2443.                 sprintf(t, "%s/%s", Dzones, t1);
  2444.                 t3 = t - 1;
  2445.                 while (*++t3)
  2446.                     if (*t3 == '\\')
  2447.                         *t3 = '/';
  2448.                 if (Dtrace)
  2449.                     tprintf("DNS: Looking for SOA record in %s\n", t);
  2450.                 fp = fopen(t, READ_TEXT);
  2451.                 if (fp)
  2452.                     {
  2453.                     done = 0;
  2454.                     oldrrp = NULLRR;
  2455.                     while(done == 0
  2456.                         && (frrp = get_rr(fp,oldrrp)) != NULLRR)
  2457.                         {
  2458.                         oldrrp = frrp;
  2459.                         if (frrp->type == TYPE_SOA)
  2460.                             {
  2461.                             done = 1;
  2462.                             if (dom_file == NULL)
  2463.                                 {
  2464.                                 dom_file = mallocw(sizeof(struct DOM_FILE));
  2465.                                 dom_file->next = NULL;
  2466.                                 }
  2467.                             else {
  2468.                                 t_dom_file = mallocw(sizeof(struct DOM_FILE));
  2469.                                 t_dom_file->next = dom_file;
  2470.                                 dom_file = t_dom_file;
  2471.                                 }
  2472.                             dom_file->filename = mallocw(13);
  2473.                             strcpy(dom_file->filename, t4);
  2474.                             dom_file->domain = mallocw(strlen(t2) + 2);
  2475.                             sprintf(dom_file->domain, "%s.", t2);
  2476.                             dom_file->dom_soa = frrp->rdata.soa;
  2477.                             dom_file->type = type;
  2478.                             dom_file->source = source;
  2479.                             if (Dtrace)
  2480.                                 {
  2481.                                 tprintf(" filename %s\n", dom_file->filename);
  2482.                                 tprintf(" mname %s\n", dom_file->dom_soa.mname);
  2483.                                 tprintf(" rname %s\n", dom_file->dom_soa.rname);
  2484.                                 tprintf(" serial %lu\n", dom_file->dom_soa.serial);
  2485.                                 tprintf(" refresh %lu\n", dom_file->dom_soa.refresh);
  2486.                                 tprintf(" retry %lu\n", dom_file->dom_soa.retry);
  2487.                                 tprintf(" expire %lu\n", dom_file->dom_soa.expire);
  2488.                                 tprintf(" minimum %lu\n", dom_file->dom_soa.minimum);
  2489.                                 }
  2490.                             }
  2491.                         }
  2492.                     fclose(fp);
  2493.                     }
  2494.                 else tprintf("failed to open\n");
  2495.                 }
  2496.     /* Start domain server task */
  2497.         free(t4);
  2498.         free(t2);
  2499.         free(t);
  2500.     Drx = newproc("Domain listener",1024,drx,0,NULL,NULL,0);
  2501.         }
  2502.     else tputs("DNS already running\n");
  2503.     return 0;
  2504. }
  2505.  
  2506. static int
  2507. dostopdnsserver(argc,argv,p)
  2508. int argc;
  2509. char *argv[];
  2510. void *p;
  2511. {
  2512.     if(Drx == NULLPROC)
  2513.     /* Start domain server task */
  2514.     tprintf("DNS not running\n");
  2515.     killproc(Drx);
  2516.     Drx = NULLPROC;
  2517.     return 0;
  2518. }
  2519.  
  2520. /* Free a domain message */
  2521. static void
  2522. free_dhdr(dp)
  2523. struct dhdr *dp;
  2524. {
  2525.     if(dp->qdcount != 0)
  2526.     free_rr(dp->questions);
  2527.     if(dp->ancount != 0)
  2528.     free_rr(dp->answers);
  2529.     if(dp->nscount != 0)
  2530.     free_rr(dp->authority);
  2531.     if(dp->arcount != 0)
  2532.     free_rr(dp->additional);
  2533.     free((char *)dp);
  2534. }
  2535.  
  2536. #endif
  2537.